home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / unix / volume8 / micrognu / part03 < prev    next >
Encoding:
Internet Message Format  |  1987-01-26  |  58.3 KB

  1. Subject:  v08i010:  A Micro-Emacs variant that resembles GNU Emacs
  2. Newsgroups: mod.sources
  3. Approved: mirror!rs
  4.  
  5. Submitted by: Bob Larson <seismo!usc-oberon!blarson>
  6. Mod.sources: Volume 8, Issue 10
  7. Archive-name: micrognu/Part03
  8.  
  9.  
  10. #! /bin/sh
  11. # This is a shell archive, meaning:
  12. # 1. Remove everything above the #! /bin/sh line.
  13. # 2. Save the resulting text in a file.
  14. # 3. Execute the file with /bin/sh (not csh) to create the files:
  15. #    line.c
  16. #    main.c
  17. #    paragraph.c
  18. #    random.c
  19. #    region.c
  20. #    prefix.c
  21. #    version.c
  22. #    word.c
  23. # This archive created: Sat Nov 15 15:02:19 1986
  24. export PATH; PATH=/bin:$PATH
  25. if test -f 'line.c'
  26. then
  27.     echo shar: will not over-write existing file "'line.c'"
  28. else
  29. cat << \SHAR_EOF > 'line.c'
  30. /*
  31.  *        Text line handling.
  32.  * The functions in this file
  33.  * are a general set of line management
  34.  * utilities. They are the only routines that
  35.  * touch the text. They also touch the buffer
  36.  * and window structures, to make sure that the
  37.  * necessary updating gets done. There are routines
  38.  * in this file that handle the kill buffer too.
  39.  * It isn't here for any good reason.
  40.  *
  41.  * Note that this code only updates the dot and
  42.  * mark values in the window list. Since all the code
  43.  * acts on the current window, the buffer that we
  44.  * are editing must be being displayed, which means
  45.  * that "b_nwnd" is non zero, which means that the
  46.  * dot and mark values in the buffer headers are
  47.  * nonsense.
  48.  */
  49. #include    "def.h"
  50.  
  51. #define    NBLOCK    16            /* Line block chunk size    */
  52.  
  53. #ifndef    KBLOCK
  54. #define    KBLOCK    256            /* Kill buffer block size.    */
  55. #endif
  56.  
  57. static char    *kbufp    = NULL;        /* Kill buffer data.        */
  58. static RSIZE    kused    = 0;        /* # of bytes used in KB.    */
  59. static RSIZE    ksize    = 0;        /* # of bytes allocated in KB.    */
  60. static RSIZE    kstart  = 0;        /* # of first used byte in KB.    */
  61. char    *malloc();
  62. /*
  63.  * This routine allocates a block
  64.  * of memory large enough to hold a LINE
  65.  * containing "used" characters. The block is
  66.  * always rounded up a bit. Return a pointer
  67.  * to the new block, or NULL if there isn't
  68.  * any memory left. Print a message in the
  69.  * message line if no space.
  70.  */
  71. LINE    *
  72. lalloc(used) register RSIZE used; {
  73.     register LINE    *lp;
  74.     register int    size;
  75.  
  76.     /*NOSTRICT*/
  77.     size = (NBLOCK-1+used) & ~(NBLOCK-1);
  78.     if (size == 0)                /* Assume that an empty    */
  79.         size = NBLOCK;            /* line is for type-in.    */
  80.     /*NOSTRICT*/
  81.     if ((lp=(LINE *)malloc(sizeof(LINE)+size)) == NULL) {
  82.         ewprintf("Can't get %d bytes", sizeof(LINE) + size);
  83.         return (NULL);
  84.     }
  85.     lp->l_size = size;
  86.     /*NOSTRICT*/
  87.     lp->l_used = used;
  88.     return (lp);
  89. }
  90.  
  91. /*
  92.  * Delete line "lp". Fix all of the
  93.  * links that might point at it (they are
  94.  * moved to offset 0 of the next line.
  95.  * Unlink the line from whatever buffer it
  96.  * might be in. Release the memory. The
  97.  * buffers are updated too; the magic conditions
  98.  * described in the above comments don't hold
  99.  * here.
  100.  */
  101. lfree(lp) register LINE *lp; {
  102.     register BUFFER    *bp;
  103.     register WINDOW    *wp;
  104.  
  105.     wp = wheadp;
  106.     while (wp != NULL) {
  107.         if (wp->w_linep == lp)
  108.             wp->w_linep = lp->l_fp;
  109.         if (wp->w_dotp  == lp) {
  110.             wp->w_dotp  = lp->l_fp;
  111.             wp->w_doto  = 0;
  112.         }
  113.         if (wp->w_markp == lp) {
  114.             wp->w_markp = lp->l_fp;
  115.             wp->w_marko = 0;
  116.         }
  117.         wp = wp->w_wndp;
  118.     }
  119.     bp = bheadp;
  120.     while (bp != NULL) {
  121.         if (bp->b_nwnd == 0) {
  122.             if (bp->b_dotp  == lp) {
  123.                 bp->b_dotp = lp->l_fp;
  124.                 bp->b_doto = 0;
  125.             }
  126.             if (bp->b_markp == lp) {
  127.                 bp->b_markp = lp->l_fp;
  128.                 bp->b_marko = 0;
  129.             }
  130.         }
  131.         bp = bp->b_bufp;
  132.     }
  133.     lp->l_bp->l_fp = lp->l_fp;
  134.     lp->l_fp->l_bp = lp->l_bp;
  135.     free((char *) lp);
  136. }
  137.  
  138. /*
  139.  * This routine gets called when
  140.  * a character is changed in place in the
  141.  * current buffer. It updates all of the required
  142.  * flags in the buffer and window system. The flag
  143.  * used is passed as an argument; if the buffer is being
  144.  * displayed in more than 1 window we change EDIT to
  145.  * HARD. Set MODE if the mode line needs to be
  146.  * updated (the "*" has to be set).
  147.  */
  148. lchange(flag) register int flag; {
  149.     register WINDOW    *wp;
  150.  
  151.     if (curbp->b_nwnd != 1)            /* Ensure hard.        */
  152.         flag = WFHARD;
  153.     if ((curbp->b_flag&BFCHG) == 0) {    /* First change, so     */
  154.         flag |= WFMODE;            /* update mode lines.    */
  155.         curbp->b_flag |= BFCHG;
  156.     }
  157.     wp = wheadp;
  158.     while (wp != NULL) {
  159.         if (wp->w_bufp == curbp)
  160.             wp->w_flag |= flag;
  161.         wp = wp->w_wndp;
  162.     }
  163. }
  164.  
  165. /*
  166.  * Insert "n" copies of the character "c"
  167.  * at the current location of dot. In the easy case
  168.  * all that happens is the text is stored in the line.
  169.  * In the hard case, the line has to be reallocated.
  170.  * When the window list is updated, take special
  171.  * care; I screwed it up once. You always update dot
  172.  * in the current window. You update mark, and a
  173.  * dot in another window, if it is greater than
  174.  * the place where you did the insert. Return TRUE
  175.  * if all is well, and FALSE on errors.
  176.  */
  177. linsert(n, c) RSIZE n; {
  178.     register char    *cp1;
  179.     register char    *cp2;
  180.     register LINE    *lp1;
  181.     register LINE    *lp2;
  182.     register LINE    *lp3;
  183.     register int    doto;
  184.     register RSIZE    i;
  185.     register WINDOW    *wp;
  186.  
  187.     lchange(WFEDIT);
  188.     lp1 = curwp->w_dotp;            /* Current line        */
  189.     if (lp1 == curbp->b_linep) {        /* At the end: special    */
  190.         if (curwp->w_doto != 0) {
  191.             ewprintf("bug: linsert");
  192.             return (FALSE);
  193.         }
  194.         if ((lp2=lalloc(n)) == NULL)    /* Allocate new line    */
  195.             return (FALSE);
  196.         lp3 = lp1->l_bp;        /* Previous line    */
  197.         lp3->l_fp = lp2;        /* Link in        */
  198.         lp2->l_fp = lp1;
  199.         lp1->l_bp = lp2;
  200.         lp2->l_bp = lp3;
  201.         for (i=0; i<n; ++i)
  202.             lp2->l_text[i] = c;
  203.         wp = wheadp;            /* Update windows    */
  204.         while (wp != NULL) {
  205.             if (wp->w_linep == lp1)
  206.                 wp->w_linep = lp2;
  207.             if (wp->w_dotp == lp1)
  208.                 wp->w_dotp = lp2;
  209.             if (wp->w_markp == lp1)
  210.                 wp->w_markp = lp2;
  211.             wp = wp->w_wndp;
  212.         }
  213.         /*NOSTRICT*/
  214.         curwp->w_doto = n;
  215.         return (TRUE);
  216.     }
  217.     doto = curwp->w_doto;            /* Save for later.    */
  218.     /*NOSTRICT (2) */
  219.     if (lp1->l_used+n > lp1->l_size) {    /* Hard: reallocate    */
  220.         if ((lp2=lalloc((RSIZE) (lp1->l_used+n))) == NULL)
  221.             return (FALSE);
  222.         cp1 = &lp1->l_text[0];
  223.         cp2 = &lp2->l_text[0];
  224.         while (cp1 != &lp1->l_text[doto])
  225.             *cp2++ = *cp1++;
  226.         /*NOSTRICT*/
  227.         cp2 += n;
  228.         while (cp1 != &lp1->l_text[lp1->l_used])
  229.             *cp2++ = *cp1++;
  230.         lp1->l_bp->l_fp = lp2;
  231.         lp2->l_fp = lp1->l_fp;
  232.         lp1->l_fp->l_bp = lp2;
  233.         lp2->l_bp = lp1->l_bp;
  234.         free((char *) lp1);
  235.     } else {                /* Easy: in place    */
  236.         lp2 = lp1;            /* Pretend new line    */
  237.         /*NOSTRICT*/
  238.         lp2->l_used += n;
  239.         cp2 = &lp1->l_text[lp1->l_used];
  240.  
  241.         cp1 = cp2-n;
  242.         while (cp1 != &lp1->l_text[doto])
  243.             *--cp2 = *--cp1;
  244.     }
  245.     for (i=0; i<n; ++i)            /* Add the characters    */
  246.         lp2->l_text[doto+i] = c;
  247.     wp = wheadp;                /* Update windows    */
  248.     while (wp != NULL) {
  249.         if (wp->w_linep == lp1)
  250.             wp->w_linep = lp2;
  251.         if (wp->w_dotp == lp1) {
  252.             wp->w_dotp = lp2;
  253.             if (wp==curwp || wp->w_doto>doto)
  254.                 /*NOSTRICT*/
  255.                 wp->w_doto += n;
  256.         }
  257.         if (wp->w_markp == lp1) {
  258.             wp->w_markp = lp2;
  259.             if (wp->w_marko > doto)
  260.                 /*NOSTRICT*/
  261.                 wp->w_marko += n;
  262.         }
  263.         wp = wp->w_wndp;
  264.     }
  265.     return (TRUE);
  266. }
  267.  
  268. /*
  269.  * Insert a newline into the buffer
  270.  * at the current location of dot in the current
  271.  * window. The funny ass-backwards way it does things
  272.  * is not a botch; it just makes the last line in
  273.  * the file not a special case. Return TRUE if everything
  274.  * works out and FALSE on error (memory allocation
  275.  * failure). The update of dot and mark is a bit
  276.  * easier then in the above case, because the split
  277.  * forces more updating.
  278.  */
  279. lnewline() {
  280.     register char    *cp1;
  281.     register char    *cp2;
  282.     register LINE    *lp1;
  283.     register LINE    *lp2;
  284.     register int    doto;
  285.     register WINDOW    *wp;
  286.  
  287.     lchange(WFHARD);
  288.     lp1  = curwp->w_dotp;            /* Get the address and    */
  289.     doto = curwp->w_doto;            /* offset of "."    */
  290.     if ((lp2=lalloc((RSIZE) doto)) == NULL)    /* New first half line    */
  291.         return (FALSE);
  292.     cp1 = &lp1->l_text[0];            /* Shuffle text around    */
  293.     cp2 = &lp2->l_text[0];
  294.     while (cp1 != &lp1->l_text[doto])
  295.         *cp2++ = *cp1++;
  296.     cp2 = &lp1->l_text[0];
  297.     while (cp1 != &lp1->l_text[lp1->l_used])
  298.         *cp2++ = *cp1++;
  299.     lp1->l_used -= doto;
  300.     lp2->l_bp = lp1->l_bp;
  301.     lp1->l_bp = lp2;
  302.     lp2->l_bp->l_fp = lp2;
  303.     lp2->l_fp = lp1;
  304.     wp = wheadp;                /* Windows        */
  305.     while (wp != NULL) {
  306.         if (wp->w_linep == lp1)
  307.             wp->w_linep = lp2;
  308.         if (wp->w_dotp == lp1) {
  309.             if (wp->w_doto < doto)
  310.                 wp->w_dotp = lp2;
  311.             else
  312.                 wp->w_doto -= doto;
  313.         }
  314.         if (wp->w_markp == lp1) {
  315.             if (wp->w_marko < doto)
  316.                 wp->w_markp = lp2;
  317.             else
  318.                 wp->w_marko -= doto;
  319.         }
  320.         wp = wp->w_wndp;
  321.     }    
  322.     return (TRUE);
  323. }
  324.  
  325. /*
  326.  * This function deletes "n" bytes,
  327.  * starting at dot. It understands how do deal
  328.  * with end of lines, etc. It returns TRUE if all
  329.  * of the characters were deleted, and FALSE if
  330.  * they were not (because dot ran into the end of
  331.  * the buffer. The "kflag" indicates either no insertion,
  332.  * or direction of insertion into the kill buffer.
  333.  */
  334. ldelete(n, kflag) RSIZE n; {
  335.     register char    *cp1;
  336.     register char    *cp2;
  337.     register LINE    *dotp;
  338.     register int    doto;
  339.     register RSIZE    chunk;
  340.     register WINDOW    *wp;
  341.  
  342.     /*
  343.      * HACK - doesn't matter, and fixes back-over-nl bug for empty
  344.      *    kill buffers.
  345.      */
  346.     if (kused == kstart) kflag = KFORW;
  347.  
  348.     while (n != 0) {
  349.         dotp = curwp->w_dotp;
  350.         doto = curwp->w_doto;
  351.         if (dotp == curbp->b_linep)    /* Hit end of buffer.    */
  352.             return (FALSE);
  353.         chunk = dotp->l_used-doto;    /* Size of chunk.    */
  354.         if (chunk > n)
  355.             chunk = n;
  356.         if (chunk == 0) {        /* End of line, merge.    */
  357.             lchange(WFHARD);
  358.             if (ldelnewline() == FALSE
  359.             || (kflag!=KNONE && kinsert('\n', kflag)==FALSE))
  360.                 return (FALSE);
  361.             --n;
  362.             continue;
  363.         }
  364.         lchange(WFEDIT);
  365.         cp1 = &dotp->l_text[doto];    /* Scrunch text.    */
  366.         cp2 = cp1 + chunk;
  367.         if (kflag == KFORW) {
  368.             while (ksize - kused < chunk)
  369.                 if (kgrow(FALSE) == FALSE) return FALSE;
  370.             bcopy(cp1, &(kbufp[kused]), (int) chunk);
  371.             kused += chunk;
  372.         } else if (kflag == KBACK) {
  373.             while (kstart < chunk)
  374.                 if (kgrow(TRUE) == FALSE) return FALSE;
  375.             bcopy(cp1, &(kbufp[kstart-chunk]), (int) chunk);
  376.             kstart -= chunk;
  377.         } else if (kflag != KNONE) panic("broken ldelete call");
  378.         while (cp2 != &dotp->l_text[dotp->l_used])
  379.             *cp1++ = *cp2++;
  380.         dotp->l_used -= (int) chunk;
  381.         wp = wheadp;            /* Fix windows        */
  382.         while (wp != NULL) {
  383.             if (wp->w_dotp==dotp && wp->w_doto>=doto) {
  384.                 /*NOSTRICT*/
  385.                 wp->w_doto -= chunk;
  386.                 if (wp->w_doto < doto)
  387.                     wp->w_doto = doto;
  388.             }    
  389.             if (wp->w_markp==dotp && wp->w_marko>=doto) {
  390.                 /*NOSTRICT*/
  391.                 wp->w_marko -= chunk;
  392.                 if (wp->w_marko < doto)
  393.                     wp->w_marko = doto;
  394.             }
  395.             wp = wp->w_wndp;
  396.         }
  397.         n -= chunk;
  398.     }
  399.     return (TRUE);
  400. }
  401.  
  402. /*
  403.  * Delete a newline. Join the current line
  404.  * with the next line. If the next line is the magic
  405.  * header line always return TRUE; merging the last line
  406.  * with the header line can be thought of as always being a
  407.  * successful operation, even if nothing is done, and this makes
  408.  * the kill buffer work "right". Easy cases can be done by
  409.  * shuffling data around. Hard cases require that lines be moved
  410.  * about in memory. Return FALSE on error and TRUE if all
  411.  * looks ok.
  412.  */
  413. ldelnewline() {
  414.     register char    *cp1;
  415.     register char    *cp2;
  416.     register LINE    *lp1;
  417.     register LINE    *lp2;
  418.     register LINE    *lp3;
  419.     register WINDOW    *wp;
  420.  
  421.     lp1 = curwp->w_dotp;
  422.     lp2 = lp1->l_fp;
  423.     if (lp2 == curbp->b_linep) {        /* At the buffer end.    */
  424.         if (lp1->l_used == 0)        /* Blank line.        */
  425.             lfree(lp1);
  426.         return (TRUE);
  427.     }
  428.     if (lp2->l_used <= lp1->l_size-lp1->l_used) {
  429.         cp1 = &lp1->l_text[lp1->l_used];
  430.         cp2 = &lp2->l_text[0];
  431.         while (cp2 != &lp2->l_text[lp2->l_used])
  432.             *cp1++ = *cp2++;
  433.         wp = wheadp;
  434.         while (wp != NULL) {
  435.             if (wp->w_linep == lp2)
  436.                 wp->w_linep = lp1;
  437.             if (wp->w_dotp == lp2) {
  438.                 wp->w_dotp  = lp1;
  439.                 wp->w_doto += lp1->l_used;
  440.             }
  441.             if (wp->w_markp == lp2) {
  442.                 wp->w_markp  = lp1;
  443.                 wp->w_marko += lp1->l_used;
  444.             }
  445.             wp = wp->w_wndp;
  446.         }        
  447.         lp1->l_used += lp2->l_used;
  448.         lp1->l_fp = lp2->l_fp;
  449.         lp2->l_fp->l_bp = lp1;
  450.         free((char *) lp2);
  451.         return (TRUE);
  452.     }
  453.     if ((lp3=lalloc((RSIZE) (lp1->l_used+lp2->l_used))) == NULL)
  454.         return (FALSE);
  455.     cp1 = &lp1->l_text[0];
  456.     cp2 = &lp3->l_text[0];
  457.     while (cp1 != &lp1->l_text[lp1->l_used])
  458.         *cp2++ = *cp1++;
  459.     cp1 = &lp2->l_text[0];
  460.     while (cp1 != &lp2->l_text[lp2->l_used])
  461.         *cp2++ = *cp1++;
  462.     lp1->l_bp->l_fp = lp3;
  463.     lp3->l_fp = lp2->l_fp;
  464.     lp2->l_fp->l_bp = lp3;
  465.     lp3->l_bp = lp1->l_bp;
  466.     wp = wheadp;
  467.     while (wp != NULL) {
  468.         if (wp->w_linep==lp1 || wp->w_linep==lp2)
  469.             wp->w_linep = lp3;
  470.         if (wp->w_dotp == lp1)
  471.             wp->w_dotp  = lp3;
  472.         else if (wp->w_dotp == lp2) {
  473.             wp->w_dotp  = lp3;
  474.             wp->w_doto += lp1->l_used;
  475.         }
  476.         if (wp->w_markp == lp1)
  477.             wp->w_markp  = lp3;
  478.         else if (wp->w_markp == lp2) {
  479.             wp->w_markp  = lp3;
  480.             wp->w_marko += lp1->l_used;
  481.         }
  482.         wp = wp->w_wndp;
  483.     }
  484.     free((char *) lp1);
  485.     free((char *) lp2);
  486.     return (TRUE);
  487. }
  488.  
  489. /*
  490.  * Replace plen characters before dot with argument string.
  491.  * Control-J characters in st are interpreted as newlines.
  492.  * There is a casehack disable flag (normally it likes to match
  493.  * case of replacement to what was there).
  494.  */
  495. lreplace(plen, st, f)
  496. register RSIZE    plen;            /* length to remove        */
  497. char        *st;            /* replacement string        */
  498. int        f;            /* case hack disable        */
  499. {
  500.     register RSIZE    rlen;        /* replacement length        */
  501.     register int    rtype;        /* capitalization         */
  502.     register int    c;        /* used for random characters    */
  503.     register int    doto;        /* offset into line        */
  504.  
  505.     /*
  506.      * Find the capitalization of the word that was found.
  507.      * f says use exact case of replacement string (same thing that
  508.      * happens with lowercase found), so bypass check.
  509.      */
  510.     /*NOSTRICT*/
  511.     (VOID) backchar(TRUE, (int) plen, KRANDOM);
  512.     rtype = _L;
  513.     c = lgetc(curwp->w_dotp, curwp->w_doto);
  514.     if (ISUPPER(c)!=FALSE  &&  f==FALSE) {
  515.         rtype = _U|_L;
  516.         if (curwp->w_doto+1 < llength(curwp->w_dotp)) {
  517.             c = lgetc(curwp->w_dotp, curwp->w_doto+1);
  518.             if (ISUPPER(c) != FALSE) {
  519.                 rtype = _U;
  520.             }
  521.         }
  522.     }
  523.  
  524.     /*
  525.      * make the string lengths match (either pad the line
  526.      * so that it will fit, or scrunch out the excess).
  527.      * be careful with dot's offset.
  528.      */
  529.     rlen = strlen(st);
  530.     doto = curwp->w_doto;
  531.     if (plen > rlen)
  532.         (VOID) ldelete((RSIZE) (plen-rlen), KNONE);
  533.     else if (plen < rlen) {
  534.         if (linsert((RSIZE) (rlen-plen), ' ') == FALSE)
  535.             return (FALSE);
  536.     }
  537.     curwp->w_doto = doto;
  538.  
  539.     /*
  540.      * do the replacement:  If was capital, then place first 
  541.      * char as if upper, and subsequent chars as if lower.  
  542.      * If inserting upper, check replacement for case.
  543.      */
  544.     while ((c = *st++&0xff) != '\0') {
  545.         if ((rtype&_U)!=0  &&  ISLOWER(c)!=0)
  546.             c = TOUPPER(c);
  547.         if (rtype == (_U|_L))
  548.             rtype = _L;
  549.         if (c == SEOL) {
  550.             if (curwp->w_doto == llength(curwp->w_dotp))
  551.                 (VOID) forwchar(FALSE, 1, KRANDOM);
  552.             else {
  553.                 if (ldelete((RSIZE) 1, KNONE) != FALSE)
  554.                     (VOID) lnewline();
  555.             }
  556.         } else if (curwp->w_dotp == curbp->b_linep) {
  557.             (VOID) linsert((RSIZE) 1, c);
  558.         } else if (curwp->w_doto == llength(curwp->w_dotp)) {
  559.             if (ldelete((RSIZE) 1, KNONE) != FALSE)
  560.                 (VOID) linsert((RSIZE) 1, c);
  561.         } else
  562.             lputc(curwp->w_dotp, curwp->w_doto++, c);
  563.     }
  564.     lchange(WFHARD);
  565.     return (TRUE);
  566. }
  567.  
  568. /*
  569.  * Delete all of the text
  570.  * saved in the kill buffer. Called by commands
  571.  * when a new kill context is being created. The kill
  572.  * buffer array is released, just in case the buffer has
  573.  * grown to immense size. No errors.
  574.  */
  575. kdelete() {
  576.     if (kbufp != NULL) {
  577.         free((char *) kbufp);
  578.         kbufp = NULL;
  579.         kstart = kused = ksize = 0;
  580.     }
  581. }
  582.  
  583. /*
  584.  * Insert a character to the kill buffer,
  585.  * enlarging the buffer if there isn't any room. Always
  586.  * grow the buffer in chunks, on the assumption that if you
  587.  * put something in the kill buffer you are going to put
  588.  * more stuff there too later. Return TRUE if all is
  589.  * well, and FALSE on errors. Print a message on
  590.  * errors. Dir says whether to put it at back or front.
  591.  */
  592. kinsert(c, dir) {
  593.  
  594.     if (kused == ksize && dir == KFORW && kgrow(FALSE) == FALSE)
  595.         return FALSE;
  596.     if (kstart == 0 && dir == KBACK && kgrow(TRUE) == FALSE)
  597.         return FALSE;
  598.     if (dir == KFORW) kbufp[kused++] = c;
  599.     else if (dir == KBACK) kbufp[--kstart] = c;
  600.     else panic("broken kinsert call");        /* Oh shit! */
  601.     return (TRUE);
  602. }
  603.  
  604. /*
  605.  * kgrow - just get more kill buffer for the callee. back is true if
  606.  * we are trying to get space at the beginning of the kill buffer.
  607.  */
  608. kgrow(back) {
  609.     register int    nstart;
  610.     register char    *nbufp;
  611.  
  612.     if ((nbufp=malloc((int)(ksize+KBLOCK))) == NULL) {
  613.         ewprintf("Can't get %ld bytes", (long)(ksize+KBLOCK));
  614.         return (FALSE);
  615.     }
  616.     nstart = (back == TRUE) ? (kstart + KBLOCK) : (KBLOCK / 4) ;
  617.     bcopy(&(kbufp[kstart]), &(nbufp[nstart]), (int) (kused-kstart));
  618.     if (kbufp != NULL)
  619.         free((char *) kbufp);
  620.     kbufp  = nbufp;
  621.     ksize += KBLOCK;
  622.     kused = kused - kstart + nstart;
  623.     kstart = nstart;
  624.     return TRUE;
  625. }
  626.  
  627. /*
  628.  * This function gets characters from
  629.  * the kill buffer. If the character index "n" is
  630.  * off the end, it returns "-1". This lets the caller
  631.  * just scan along until it gets a "-1" back.
  632.  */
  633. kremove(n) {
  634.     if (n < 0 || n + kstart >= kused)
  635.         return (-1);
  636.     return (kbufp[n + kstart] & 0xFF);
  637. }
  638. SHAR_EOF
  639. fi # end of overwriting check
  640. if test -f 'main.c'
  641. then
  642.     echo shar: will not over-write existing file "'main.c'"
  643. else
  644. cat << \SHAR_EOF > 'main.c'
  645. /*
  646.  *        Mainline, macro commands.
  647.  */
  648. #include    "def.h"
  649.  
  650. int    thisflag;            /* Flags, this command        */
  651. int    lastflag;            /* Flags, last command        */
  652. int    curgoal;            /* Goal column            */
  653. BUFFER    *curbp;                /* Current buffer        */
  654. WINDOW    *curwp;                /* Current window        */
  655. BUFFER    *bheadp;            /* BUFFER listhead        */
  656. WINDOW    *wheadp = (WINDOW *)NULL;    /* WINDOW listhead        */
  657. KEY    kbdm[NKBDM] = {(KCTLX|')')};    /* Macro            */
  658. KEY    *kbdmip;            /* Input  for above        */
  659. KEY    *kbdmop;            /* Output for above        */
  660. char    pat[NPAT];            /* Pattern            */
  661. #ifdef    HASH
  662. SYMBOL    *symbol[NSHASH];        /* Symbol table listhead.    */
  663. #else
  664. /* should really be a *symbol, but don't want to break the hash code yet */
  665. SYMBOL    *symbol[1];
  666. #endif
  667. SYMBOL    *binding[NKEYS];        /* Key bindings.        */
  668. #ifdef    DPROMPT
  669. extern char prompt[], *promptp;        /* delayed prompting        */
  670. #endif
  671.  
  672. main(argc, argv) char *argv[]; {
  673.     register KEY    c;
  674.     register int    f;
  675.     register int    n;
  676.     register int    mflag;
  677. #ifdef    STARTUP
  678.     char        *sfile, *startupfile();
  679. #endif
  680.     char        bname[NBUFN];
  681.  
  682. #ifdef SYSINIT
  683.     SYSINIT;                /* system dependent.    */
  684. #endif
  685.     vtinit();                /* Virtual terminal.    */
  686.     edinit();                /* Buffers, windows.    */
  687.     keymapinit();                /* Symbols, bindings.    */
  688.     /* doing update() before reading files causes the error messages from
  689.      * the file I/O show up on the screen.  (and also an extra display
  690.      * of the mode line if there are files specified on the command line.)
  691.      */
  692.     update();
  693. #ifdef    STARTUP                    /* User startup file.    */
  694.     if ((sfile = startupfile()) != NULL)
  695.         (VOID) load(sfile);
  696. #endif
  697.     while (--argc > 0) {
  698.         makename(bname, *++argv);
  699.         curbp = bfind(bname, TRUE);
  700.         (VOID) showbuffer(curbp, curwp, 0);
  701.         (VOID) readin(*argv);
  702.     }
  703.     lastflag = 0;                /* Fake last flags.    */
  704. loop:
  705. #ifdef    DPROMPT
  706.     *(promptp = prompt) = '\0';
  707.     if(epresf == KPROMPT) eerase();
  708. #endif
  709.     update();                /* Fix up the screen.    */
  710.     c = getkey(KPROMPT);
  711.     if (epresf == TRUE) {
  712.         eerase();
  713.         update();
  714.     }
  715.     f = FALSE;
  716.     n = 1;
  717.     if (((KMETA|'0') <= c && c <= (KMETA|'9')) || c == (KMETA|'-')) {
  718.         f = TRUE;
  719.         c = c & ~KMETA;
  720.     } else if (c == (KCTRL|'U')) {
  721.         f = TRUE;
  722.         n = 4;
  723.         while ((c=getkey(KNOMAC | KPROMPT)) == (KCTRL|'U')) 
  724.             n *= 4;
  725.     }
  726.     if (f == TRUE) {
  727.         if ((c>='0' && c<='9') || c=='-') {
  728.             if (c == '-') {
  729.                 n = 0;
  730.                 mflag = TRUE;
  731.             } else {
  732.                 n = ((int) c) - '0';
  733.                 mflag = FALSE;
  734.             }
  735.             while ((c=getkey(KNOMAC | KPROMPT))>='0' && c<='9')
  736.                 n = 10*n + ((int) c) - '0';
  737.             if (mflag != FALSE)
  738.                 n = -n;
  739.         }
  740.     }
  741.     if (kbdmip != NULL) {            /* Terminate macros.    */
  742.         if (c!=(KCTLX|')') && kbdmip>&kbdm[NKBDM-6]) {
  743.             (VOID) ctrlg(FALSE, 0, KRANDOM);
  744.             goto loop;
  745.         }
  746.         if (f != FALSE) {
  747.             kbdmip[-1] = (KEY) (KCTRL|'U');/* overwrite ESC */
  748.             *kbdmip++ = (KEY) n;
  749.             *kbdmip++ = (KEY) c;
  750.         }
  751.     }
  752.     switch (execute(c, f, n)) {        /* Do it.        */
  753.         case TRUE: break;
  754.         case ABORT:
  755.                ewprintf("Quit");    /* and fall through */
  756.         case FALSE: default:
  757.                ttbeep();
  758.                if (kbdmip != NULL) {
  759.                    kbdm[0] = (KEY) (KCTLX|')');
  760.                    kbdmip = NULL;
  761.                }
  762.     }
  763.     goto loop;
  764. }
  765.  
  766. /*
  767.  * Command execution. Look up the binding in the the
  768.  * binding array, and do what it says. Return a very bad status
  769.  * if there is no binding, or if the symbol has a type that
  770.  * is not usable (there is no way to get this into a symbol table
  771.  * entry now). Also fiddle with the flags.
  772.  */
  773. execute(c, f, n) KEY c; {
  774.     register SYMBOL    *sp;
  775.     register int    status;
  776.  
  777.     if ((sp=binding[c]) != NULL) {
  778.         thisflag = 0;
  779.         status = (*sp->s_funcp)(f, n, c);
  780.         lastflag = thisflag;
  781.         return (status);
  782.     }
  783.     lastflag = 0;
  784.     return (FALSE);
  785. }
  786.  
  787. /*
  788.  * Initialize all of the buffers
  789.  * and windows. The buffer name is passed down as
  790.  * an argument, because the main routine may have been
  791.  * told to read in a file by default, and we want the
  792.  * buffer name to be right.
  793.  */
  794. edinit() {
  795.     register BUFFER    *bp;
  796.     register WINDOW    *wp;
  797.  
  798.     bheadp = NULL;
  799.     bp = bfind("*scratch*", TRUE);        /* Text buffer.        */
  800.     wp = (WINDOW *)malloc(sizeof(WINDOW));    /* Initial window.    */
  801.     if (bp==NULL || wp==NULL) panic("edinit");
  802.     curbp  = bp;                /* Current ones.    */
  803.     wheadp = wp;
  804.     curwp  = wp;
  805.     wp->w_wndp  = NULL;            /* Initialize window.    */
  806.     wp->w_bufp  = bp;
  807.     bp->b_nwnd  = 1;            /* Displayed.        */
  808.     wp->w_linep = bp->b_linep;
  809.     wp->w_dotp  = bp->b_linep;
  810.     wp->w_doto  = 0;
  811.     wp->w_markp = NULL;
  812.     wp->w_marko = 0;
  813.     wp->w_toprow = 0;
  814.     wp->w_ntrows = nrow-2;            /* 2 = mode, echo.    */
  815.     wp->w_force = 0;
  816.     wp->w_flag  = WFMODE|WFHARD;        /* Full.        */
  817. }
  818.  
  819. /*
  820.  * Quit command. If an argument, always
  821.  * quit. Otherwise confirm if a buffer has been
  822.  * changed and not written out. Normally bound
  823.  * to "C-X C-C".
  824.  */
  825. /*ARGSUSED*/
  826. quit(f, n, k) {
  827.     register int    s;
  828.  
  829.     if ((s = anycb(FALSE)) == ABORT) return ABORT;
  830.     if (s == FALSE
  831.     || eyesno("Some modified buffers exist, really exit") == TRUE) {
  832.         vttidy();
  833.         exit(GOOD);
  834.     }
  835.     return TRUE;
  836. }
  837.  
  838. /*
  839.  * Begin a keyboard macro.
  840.  * Error if not at the top level
  841.  * in keyboard processing. Set up
  842.  * variables and return.
  843.  */
  844. /*ARGSUSED*/
  845. ctlxlp(f, n, k) {
  846.     if (kbdmip!=NULL || kbdmop!=NULL) {
  847.         ewprintf("Already defining kbd macro!");
  848.         return (FALSE);
  849.     }
  850.     ewprintf("Defining kbd macro...");
  851.     kbdmip = &kbdm[0];
  852.     return (TRUE);
  853. }
  854.  
  855. /*
  856.  * End keyboard macro. Check for
  857.  * the same limit conditions as the
  858.  * above routine. Set up the variables
  859.  * and return to the caller.
  860.  */
  861. /*ARGSUSED*/
  862. ctlxrp(f, n, k) {
  863.     if (kbdmip == NULL) {
  864.         ewprintf("Not defining kbd macro.");
  865.         return (FALSE);
  866.     }
  867.     ewprintf("Keyboard macro defined");
  868.     kbdmip = NULL;
  869.     return (TRUE);
  870. }
  871.  
  872. /*
  873.  * Execute a macro.
  874.  * The command argument is the
  875.  * number of times to loop. Quit as
  876.  * soon as a command gets an error.
  877.  * Return TRUE if all ok, else
  878.  * FALSE.
  879.  */
  880. /*ARGSUSED*/
  881. ctlxe(f, n, k) {
  882.     register KEY    c;
  883.     register int    af;
  884.     register int    an;
  885.     register int    s;
  886.  
  887.     if (kbdmip!=NULL || kbdmop!=NULL) {
  888.         ewprintf("Not now");
  889.         return (FALSE);
  890.     }
  891.     if (n < 0) 
  892.         return (TRUE);
  893.     do {
  894.         kbdmop = &kbdm[0];
  895.         do {
  896.             af = FALSE;
  897.             an = 1;
  898.             if ((c = *kbdmop++) == (KCTRL|'U')) {
  899.                 af = TRUE;
  900.                 an = (int) *kbdmop++;
  901.                 c  = *kbdmop++;
  902.             }
  903.             s = TRUE;
  904.         } while (c!=(KCTLX|')') && (s=execute(c, af, an))==TRUE);
  905.         kbdmop = NULL;
  906.     } while (s==TRUE && --n);
  907.     return (s);
  908. }
  909.  
  910. /*
  911.  * User abort. Should be called by any input routine that sees a C-g
  912.  * to abort whatever C-g is aborting these days. Currently does
  913.  * nothing.
  914.  */
  915. /*ARGSUSED*/
  916. ctrlg(f, n, k) {
  917.     return (ABORT);
  918. }
  919.  
  920. /*
  921.  * Display the version. All this does
  922.  * is copy the version string onto the echo line.
  923.  */
  924. /*ARGSUSED*/
  925. showversion(f, n, k) {
  926.  
  927.     ewprintf(version);
  928.     return TRUE ;
  929. }
  930. SHAR_EOF
  931. fi # end of overwriting check
  932. if test -f 'paragraph.c'
  933. then
  934.     echo shar: will not over-write existing file "'paragraph.c'"
  935. else
  936. cat << \SHAR_EOF > 'paragraph.c'
  937. /*
  938.  * Code for dealing with paragraphs and filling. Adapted from MicroEMACS 3.6
  939.  * and GNU-ified by mwm@ucbvax.  Several bug fixes by blarson@usc-oberon.
  940.  */
  941. #include "def.h"
  942.  
  943. static int    fillcol = 70 ;
  944. #define    MAXWORD    256
  945.  
  946. /*
  947.  * go back to the begining of the current paragraph
  948.  * here we look for a <NL><NL> or <NL><TAB> or <NL><SPACE>
  949.  * combination to delimit the begining of a paragraph
  950.  */
  951. /*ARGSUSED*/
  952. gotobop(f, n, k) {
  953.     register int suc;    /* success of last backchar */
  954.  
  955.     if (n < 0)    /* the other way...*/
  956.         return(gotoeop(f, -n, KRANDOM));
  957.  
  958.     while (n-- > 0) {    /* for each one asked for */
  959.  
  960.         /* first scan back until we are in a word */
  961.         suc = backchar(FALSE, 1, KRANDOM);
  962.         while (!inword() && suc)
  963.             suc = backchar(FALSE, 1, KRANDOM);
  964.         curwp->w_doto = 0;    /* and go to the B-O-Line */
  965.  
  966.         /* and scan back until we hit a <NL><SP> <NL><TAB> or <NL><NL> */
  967.         while (lback(curwp->w_dotp) != curbp->b_linep)
  968.             if (llength(lback(curwp->w_dotp)) 
  969.                 && lgetc(curwp->w_dotp,0) != ' '
  970.                 && lgetc(curwp->w_dotp,0) != '\t')
  971.                 curwp->w_dotp = lback(curwp->w_dotp);
  972.             else
  973.                 break;
  974.     }
  975.     curwp->w_flag |= WFMOVE;    /* force screen update */
  976.     return TRUE;
  977. }
  978.  
  979. /*
  980.  * go forword to the end of the current paragraph
  981.  * here we look for a <NL><NL> or <NL><TAB> or <NL><SPACE>
  982.  * combination to delimit the begining of a paragraph
  983.  */
  984. /*ARGSUSED*/
  985. gotoeop(f, n, k) {
  986.     register int suc;    /* success of last backchar */
  987.  
  988.     if (n < 0)    /* the other way...*/
  989.         return(gotobop(f, -n, KRANDOM));
  990.  
  991.     while (n-- > 0) {    /* for each one asked for */
  992.  
  993.         /* Find the first word on/after the current line */
  994.         curwp->w_doto = 0;
  995.         suc = forwchar(FALSE, 1, KRANDOM);
  996.         while (!inword() && suc)
  997.             suc = forwchar(FALSE, 1, KRANDOM);
  998.         curwp->w_doto = 0;
  999.         if (curwp->w_dotp == curbp->b_linep)
  1000.             break;                /* check for eob */
  1001.         curwp->w_dotp = lforw(curwp->w_dotp);
  1002.  
  1003.         /* and scan forword until we hit a <NL><SP> or ... */
  1004.         while (curwp->w_dotp != curbp->b_linep) {
  1005.             if (llength(curwp->w_dotp)
  1006.                 && lgetc(curwp->w_dotp,0) != ' '
  1007.                 && lgetc(curwp->w_dotp,0) != '\t')
  1008.                 curwp->w_dotp = lforw(curwp->w_dotp);
  1009.             else
  1010.                 break;
  1011.         }
  1012.     }
  1013.     curwp->w_flag |= WFMOVE;    /* force screen update */
  1014.     return TRUE;
  1015. }
  1016.  
  1017. /*
  1018.  * Fill the current paragraph according to the current
  1019.  * fill column
  1020.  */
  1021. /*ARGSUSED*/
  1022. fillpara(f, n, k) {
  1023.     register int    c;        /* current char durring scan    */
  1024.     register int    wordlen;    /* length of current word    */
  1025.     register int    clength;    /* position on line during fill    */
  1026.     register int    i;        /* index during word copy    */
  1027.     register int    eopflag;    /* Are we at the End-Of-Paragraph? */
  1028.     int         firstflag;    /* first word? (needs no space)    */
  1029.     int        newlength;    /* tentative new line length    */
  1030.     int        eolflag;    /* was at end of line        */
  1031.     LINE         *eopline;    /* pointer to line just past EOP */
  1032.     char wbuf[MAXWORD];        /* buffer for current word    */
  1033.  
  1034.     /* record the pointer to the line just past the EOP */
  1035.     (VOID) gotoeop(FALSE, 1, KRANDOM);
  1036.     eopline = curwp->w_dotp;
  1037.  
  1038.     /* and back top the begining of the paragraph */
  1039.     (VOID) gotobop(FALSE, 1, KRANDOM);
  1040.  
  1041.     /* initialize various info */
  1042.     i = TRUE;
  1043.     while (i == TRUE && !inword())
  1044.         i = forwchar(FALSE, 1, KRANDOM);
  1045.     clength = curwp->w_doto;
  1046.     wordlen = 0;
  1047.  
  1048.     /* scan through lines, filling words */
  1049.     firstflag = TRUE;
  1050.     eopflag = FALSE;
  1051.     while (!eopflag) {
  1052.         /* get the next character in the paragraph */
  1053.         if (eolflag=(curwp->w_doto == llength(curwp->w_dotp))) {
  1054.             c = ' ';
  1055.             if (lforw(curwp->w_dotp) == eopline)
  1056.                 eopflag = TRUE;
  1057.         } else
  1058.             c = lgetc(curwp->w_dotp, curwp->w_doto);
  1059.  
  1060.         /* and then delete it */
  1061.         if (ldelete((RSIZE) 1, KNONE) == FALSE) return FALSE ;
  1062.  
  1063.         /* if not a separator, just add it in */
  1064.         if (c != ' ' && c != '\t') {
  1065.             if (wordlen < MAXWORD - 1)
  1066.                 wbuf[wordlen++] = c;
  1067.             else {
  1068.                 /* You loose chars beyond MAXWORD if the word
  1069.                  * is to long. I'm to lazy to fix it now; it
  1070.                  * just silently truncated the word before, so
  1071.                  * I get to feel smug.
  1072.                  */
  1073.                 ewprintf("Word too long!");
  1074.             }
  1075.         } else if (wordlen) {
  1076.             /* calculate tenatitive new length with word added */
  1077.             newlength = clength + 1 + wordlen;
  1078.             /* if at end of line or at doublespace and previous
  1079.              * character was one of '.','?','!' doublespace here.
  1080.              */
  1081.             if((eolflag || curwp->w_doto==llength(curwp->w_dotp)
  1082.                 || (c=lgetc(curwp->w_dotp,curwp->w_doto))==' '
  1083.                 || c=='\t')
  1084.               && ISEOSP(wbuf[wordlen-1])
  1085.               && wordlen<MAXWORD-1)
  1086.                 wbuf[wordlen++] = ' ';
  1087.             /* at a word break with a word waiting */
  1088.              if (newlength <= fillcol) {
  1089.                 /* add word to current line */
  1090.                 if (!firstflag) {
  1091.                     (VOID) linsert((RSIZE) 1, ' ');
  1092.                     ++clength;
  1093.                 }
  1094.                 firstflag = FALSE;
  1095.             } else {
  1096.                 if(curwp->w_doto > 0 &&
  1097.                     lgetc(curwp->w_dotp,curwp->w_doto-1)==' ') {
  1098.                         curwp->w_doto -= 1;
  1099.                     (VOID) ldelete((RSIZE) 1, KNONE);
  1100.                 }
  1101.                 /* start a new line */
  1102.                 (VOID) lnewline();
  1103.                 clength = 0;
  1104.             }
  1105.  
  1106.             /* and add the word in in either case */
  1107.             for (i=0; i<wordlen; i++) {
  1108.                 (VOID) linsert((RSIZE) 1, wbuf[i]);
  1109.                 ++clength;
  1110.             }
  1111.             wordlen = 0;
  1112.         }
  1113.     }
  1114.     /* and add a last newline for the end of our new paragraph */
  1115.     (VOID) lnewline();
  1116.     /* we realy should wind up where we started, (which is hard to keep
  1117.      * track of) but I think the end of the last line is better than the
  1118.      * begining of the blank line.     */
  1119.     (VOID) backchar(FALSE, 1, KRANDOM);
  1120.     return TRUE;
  1121. }
  1122.  
  1123. /* delete n paragraphs starting with the current one */
  1124. /*ARGSUSED*/
  1125. killpara(f, n, k) {
  1126.     register int status;    /* returned status of functions */
  1127.  
  1128.     while (n--) {        /* for each paragraph to delete */
  1129.  
  1130.         /* mark out the end and begining of the para to delete */
  1131.         (VOID) gotoeop(FALSE, 1, KRANDOM);
  1132.  
  1133.         /* set the mark here */
  1134.             curwp->w_markp = curwp->w_dotp;
  1135.             curwp->w_marko = curwp->w_doto;
  1136.  
  1137.         /* go to the begining of the paragraph */
  1138.         (VOID) gotobop(FALSE, 1, KRANDOM);
  1139.         curwp->w_doto = 0;    /* force us to the begining of line */
  1140.     
  1141.         /* and delete it */
  1142.         if ((status = killregion(FALSE, 1, KRANDOM)) != TRUE)
  1143.             return(status);
  1144.  
  1145.         /* and clean up the 2 extra lines */
  1146.         (VOID) ldelete((RSIZE) 1, KFORW);
  1147.     }
  1148.     return(TRUE);
  1149. }
  1150.  
  1151. /*
  1152.  * check to see if we're past fillcol, and if so,
  1153.  * justify this line. As a last step, justify the line.
  1154.  */
  1155. /*ARGSUSED*/
  1156. fillword(f, n, k) {
  1157.     register char    c;
  1158.     register int    col, i, nce;
  1159.  
  1160.     for (i = col = 0; col <= fillcol; ++i, ++col) {
  1161.         if (i == curwp->w_doto) return selfinsert(f, n, k) ;
  1162.         c = lgetc(curwp->w_dotp, i);
  1163.         if (c == '\t') col |= 0x07;
  1164.         else if (ISCTRL(c) != FALSE) ++col;
  1165.     }
  1166.     if (curwp->w_doto != llength(curwp->w_dotp)) {
  1167.         (VOID) selfinsert(f, n, k);
  1168.         nce = llength(curwp->w_dotp) - curwp->w_doto;
  1169.     } else nce = 0;
  1170.     curwp->w_doto = i;
  1171.  
  1172.     if ((c = lgetc(curwp->w_dotp, curwp->w_doto)) != ' ' && c != '\t')
  1173.         do {
  1174.             (VOID) backchar(FALSE, 1, KRANDOM);
  1175.         } while ((c = lgetc(curwp->w_dotp, curwp->w_doto)) != ' '
  1176.               && c != '\t' && curwp->w_doto > 0);
  1177.  
  1178.     if (curwp->w_doto == 0)
  1179.         do {
  1180.             (VOID) forwchar(FALSE, 1, KRANDOM);
  1181.         } while ((c = lgetc(curwp->w_dotp, curwp->w_doto)) != ' '
  1182.               && c != '\t' && curwp->w_doto < llength(curwp->w_dotp));
  1183.  
  1184.     (VOID) delwhite(FALSE, 1, KRANDOM);
  1185.     (VOID) backdel(FALSE, 1, KRANDOM);
  1186.     (VOID) lnewline();
  1187.     curwp->w_doto = llength(curwp->w_dotp) - nce;
  1188.     curwp->w_flag |= WFMOVE;
  1189.     if (nce == 0 && curwp->w_doto != 0) return fillword(f, n, k);
  1190.     return TRUE;
  1191. }
  1192.  
  1193. /* Set fill column to n. */
  1194. /*ARGSUSED*/
  1195. setfillcol(f, n, k) {
  1196.     extern int    getcolpos() ;
  1197.  
  1198.     fillcol = ((f == FALSE) ? getcolpos() : n);
  1199.     if (kbdmop == NULL) ewprintf("Fill column set to %d", fillcol);
  1200.         return(TRUE);
  1201. }
  1202. SHAR_EOF
  1203. fi # end of overwriting check
  1204. if test -f 'random.c'
  1205. then
  1206.     echo shar: will not over-write existing file "'random.c'"
  1207. else
  1208. cat << \SHAR_EOF > 'random.c'
  1209. /*
  1210.  *        Assorted commands.
  1211.  * The file contains the command
  1212.  * processors for a large assortment of unrelated
  1213.  * commands. The only thing they have in common is
  1214.  * that they are all command processors.
  1215.  */
  1216. #include    "def.h"
  1217.  
  1218. /*
  1219.  * Display a bunch of useful information about
  1220.  * the current location of dot. The character under the
  1221.  * cursor (in octal), the current line, row, and column, and
  1222.  * approximate position of the cursor in the file (as a percentage)
  1223.  * is displayed. The column position assumes an infinite position
  1224.  * display; it does not truncate just because the screen does.
  1225.  * This is normally bound to "C-X =".
  1226.  */
  1227. /*ARGSUSED*/
  1228. showcpos(f, n, k) {
  1229.     register LINE    *clp;
  1230.     register long    nchar;
  1231.     long        cchar;
  1232.     register int    nline, row;
  1233.     int        cline, cbyte;    /* Current line/char/byte */
  1234.     int        ratio;
  1235.     KEY        keychar();
  1236.  
  1237.     clp = lforw(curbp->b_linep);        /* Collect the data.    */
  1238.     nchar = 0;
  1239.     nline = 0;
  1240.     for (;;) {
  1241.         ++nline;            /* Count this line    */
  1242.         if (clp == curwp->w_dotp) {
  1243.             cline = nline;        /* Mark line        */
  1244.             cchar = nchar + curwp->w_doto;
  1245.             if (curwp->w_doto == llength(clp))
  1246.                 cbyte = '\n';
  1247.             else
  1248.                 cbyte = lgetc(clp, curwp->w_doto);
  1249.         }
  1250.         nchar += llength(clp) + 1;    /* Now count the chars    */
  1251.         if (clp == curbp->b_linep) break ;
  1252.         clp = lforw(clp);
  1253.     }
  1254.     row = curwp->w_toprow;            /* Determine row.    */
  1255.     clp = curwp->w_linep;
  1256.     while (clp!=curbp->b_linep && clp!=curwp->w_dotp) {
  1257.         ++row;
  1258.         clp = lforw(clp);
  1259.     }
  1260.     ++row;                    /* Convert to origin 1.    */
  1261.     /*NOSTRICT*/    
  1262.     /* nchar can't be zero (because of the "bonus" \n at end of file) */
  1263.     ratio = (100L*cchar) / nchar;
  1264.     ewprintf("Char: %c (0%o)  point=%ld(%d%%)  line=%d  row=%d  col=%d",
  1265.         (int) keychar(cbyte, FALSE), cbyte, cchar, ratio, cline, row,
  1266.         getcolpos());
  1267.     return (TRUE);
  1268. }
  1269.  
  1270. getcolpos() {
  1271.     register int    col, i, c;
  1272.  
  1273.     col = 0;                /* Determine column.    */
  1274.     for (i=0; i<curwp->w_doto; ++i) {
  1275.         c = lgetc(curwp->w_dotp, i);
  1276.         if (c == '\t')
  1277.             col |= 0x07;
  1278.         else if (ISCTRL(c) != FALSE)
  1279.             ++col;
  1280.         ++col;
  1281.     }
  1282.     return col + 1;                /* Convert to origin 1.    */
  1283. }
  1284. /*
  1285.  * Twiddle the two characters on either side of
  1286.  * dot. If dot is at the end of the line twiddle the
  1287.  * two characters before it. Return with an error if dot
  1288.  * is at the beginning of line; it seems to be a bit
  1289.  * pointless to make this work. This fixes up a very
  1290.  * common typo with a single stroke. Normally bound
  1291.  * to "C-T". This always works within a line, so
  1292.  * "WFEDIT" is good enough.
  1293.  */
  1294. /*ARGSUSED*/
  1295. twiddle(f, n, k) {
  1296.     register LINE    *dotp;
  1297.     register int    doto, odoto;
  1298.     register int    cl;
  1299.     register int    cr;
  1300.  
  1301.     dotp = curwp->w_dotp;
  1302.     odoto = doto = curwp->w_doto;
  1303.     if (doto==llength(dotp) && --doto<0)
  1304.         return (FALSE);
  1305.     cr = lgetc(dotp, doto);
  1306.     if (--doto < 0)
  1307.         return (FALSE);
  1308.     cl = lgetc(dotp, doto);
  1309.     lputc(dotp, doto+0, cr);
  1310.     lputc(dotp, doto+1, cl);
  1311.     if (odoto != llength(dotp)) ++(curwp->w_doto);
  1312.     lchange(WFEDIT);
  1313.     return (TRUE);
  1314. }
  1315.  
  1316. /*
  1317.  * Quote the next character, and
  1318.  * insert it into the buffer. All the characters
  1319.  * are taken literally, with the exception of the newline,
  1320.  * which always has its line splitting meaning. The character
  1321.  * is always read, even if it is inserted 0 times, for
  1322.  * regularity.
  1323.  */
  1324. /*ARGSUSED*/
  1325. quote(f, n, k) {
  1326.     register int    s;
  1327.     register KEY    c;
  1328.  
  1329.     if (kbdmop != NULL) c = (KEY) *kbdmop++;
  1330.     else c = getkey(KQUOTE);
  1331.     if (n < 0)
  1332.         return (FALSE);
  1333.     if (n == 0)
  1334.         return (TRUE);
  1335.     if (c == '\n') {
  1336.         do {
  1337.             s = lnewline();
  1338.         } while (s==TRUE && --n);
  1339.         return (s);
  1340.     }
  1341.     return (linsert((RSIZE) n, (char) c));
  1342. }
  1343.  
  1344. /*
  1345.  * Ordinary text characters are bound to this function,
  1346.  * which inserts them into the buffer. Characters marked as control
  1347.  * characters (using the CTRL flag) may be remapped to their ASCII
  1348.  * equivalent. This makes TAB (C-I) work right, and also makes the
  1349.  * world look reasonable if a control character is bound to this
  1350.  * this routine by hand. Any META or CTLX flags on the character
  1351.  * are discarded. This is the only routine that actually looks
  1352.  * the the "k" argument.
  1353.  */
  1354. /*ARGSUSED*/
  1355. selfinsert(f, n, k) {
  1356.     register int    c;
  1357.  
  1358.     if (n < 0)
  1359.         return (FALSE);
  1360.     if (n == 0)
  1361.         return (TRUE);
  1362.     c = k & KCHAR;
  1363.     if ((k&KCTRL)!=0 && c>='@' && c<='_')    /* ASCII-ify.        */
  1364.         c -= '@';
  1365.     return (linsert((RSIZE) n, c));
  1366. }
  1367.  
  1368. /*
  1369.  * Open up some blank space. The basic plan
  1370.  * is to insert a bunch of newlines, and then back
  1371.  * up over them. Everything is done by the subcommand
  1372.  * procerssors. They even handle the looping. Normally
  1373.  * this is bound to "C-O".
  1374.  */
  1375. /*ARGSUSED*/
  1376. openline(f, n, k) {
  1377.     register int    i;
  1378.     register int    s;
  1379.  
  1380.     if (n < 0)
  1381.         return (FALSE);
  1382.     if (n == 0)
  1383.         return (TRUE);
  1384.     i = n;                    /* Insert newlines.    */
  1385.     do {
  1386.         s = lnewline();
  1387.     } while (s==TRUE && --i);
  1388.     if (s == TRUE)                /* Then back up overtop    */
  1389.         s = backchar(f, n, KRANDOM);    /* of them all.        */
  1390.     return (s);
  1391. }
  1392.  
  1393. /*
  1394.  * Insert a newline.
  1395.  * If you are at the end of the line and the
  1396.  * next line is a blank line, just move into the
  1397.  * blank line. This makes "C-O" and "C-X C-O" work
  1398.  * nicely, and reduces the ammount of screen
  1399.  * update that has to be done. This would not be
  1400.  * as critical if screen update were a lot
  1401.  * more efficient.
  1402.  */
  1403. /*ARGSUSED*/
  1404. newline(f, n, k) {
  1405.     register LINE    *lp;
  1406.     register int    s;
  1407.  
  1408.     if (n < 0)
  1409.         return (FALSE);
  1410.     while (n--) {
  1411.         lp = curwp->w_dotp;
  1412.         if (llength(lp) == curwp->w_doto
  1413.         && lp != curbp->b_linep
  1414.         && llength(lforw(lp)) == 0) {
  1415.             if ((s=forwchar(FALSE, 1, KRANDOM)) != TRUE)
  1416.                 return (s);
  1417.         } else if ((s=lnewline()) != TRUE)
  1418.             return (s);
  1419.     }
  1420.     return (TRUE);
  1421. }
  1422.  
  1423. /*
  1424.  * Delete blank lines around dot.
  1425.  * What this command does depends if dot is
  1426.  * sitting on a blank line. If dot is sitting on a
  1427.  * blank line, this command deletes all the blank lines
  1428.  * above and below the current line. If it is sitting
  1429.  * on a non blank line then it deletes all of the
  1430.  * blank lines after the line. Normally this command
  1431.  * is bound to "C-X C-O". Any argument is ignored.
  1432.  */
  1433. /*ARGSUSED*/
  1434. deblank(f, n, k) {
  1435.     register LINE    *lp1;
  1436.     register LINE    *lp2;
  1437.     register RSIZE    nld;
  1438.  
  1439.     lp1 = curwp->w_dotp;
  1440.     while (llength(lp1)==0 && (lp2=lback(lp1))!=curbp->b_linep)
  1441.         lp1 = lp2;
  1442.     lp2 = lp1;
  1443.     nld = (RSIZE) 0;
  1444.     while ((lp2=lforw(lp2))!=curbp->b_linep && llength(lp2)==0)
  1445.         ++nld;
  1446.     if (nld == 0)
  1447.         return (TRUE);
  1448.     curwp->w_dotp = lforw(lp1);
  1449.     curwp->w_doto = 0;
  1450.     return (ldelete((RSIZE)nld, KNONE));
  1451. }
  1452.  
  1453. /*
  1454.  * Delete any whitespace around dot, then insert a space.
  1455.  */
  1456. /*ARGSUSED*/
  1457. delwhite(f, n, k) {
  1458.     register int    col, c, s;
  1459.  
  1460.     col = curwp->w_doto;
  1461.     while ((c = lgetc(curwp->w_dotp, col)) == ' ' || c == '\t')
  1462.         ++col;
  1463.     do
  1464.         if ((s = backchar(FALSE, 1, KRANDOM)) == FALSE) break;
  1465.     while ((c = lgetc(curwp->w_dotp, curwp->w_doto)) == ' ' || c == '\t') ;
  1466.  
  1467.     if (s == TRUE) (VOID) forwchar(FALSE, 1, KRANDOM);
  1468.     (VOID) ldelete((RSIZE)(col - curwp->w_doto), KNONE);
  1469.     return linsert((RSIZE) 1, ' ');
  1470. }
  1471. /*
  1472.  * Insert a newline, then enough
  1473.  * tabs and spaces to duplicate the indentation
  1474.  * of the previous line. Assumes tabs are every eight
  1475.  * characters. Quite simple. Figure out the indentation
  1476.  * of the current line. Insert a newline by calling
  1477.  * the standard routine. Insert the indentation by
  1478.  * inserting the right number of tabs and spaces.
  1479.  * Return TRUE if all ok. Return FALSE if one
  1480.  * of the subcomands failed. Normally bound
  1481.  * to "C-J".
  1482.  */
  1483. /*ARGSUSED*/
  1484. indent(f, n, k) {
  1485.     register int    nicol;
  1486.     register int    c;
  1487.     register int    i;
  1488.  
  1489.     if (n < 0)
  1490.         return (FALSE);
  1491.     while (n--) {
  1492.         nicol = 0;
  1493.         for (i=0; i<llength(curwp->w_dotp); ++i) {
  1494.             c = lgetc(curwp->w_dotp, i);
  1495.             if (c!=' ' && c!='\t')
  1496.                 break;
  1497.             if (c == '\t')
  1498.                 nicol |= 0x07;
  1499.             ++nicol;
  1500.         }
  1501.         if (lnewline() == FALSE
  1502.         || ((i=nicol/8)!=0 && linsert((RSIZE) i, '\t')==FALSE)
  1503.         || ((i=nicol%8)!=0 && linsert((RSIZE) i,  ' ')==FALSE))
  1504.             return (FALSE);
  1505.     }
  1506.     return (TRUE);
  1507. }
  1508.  
  1509. /*
  1510.  * Delete forward. This is real
  1511.  * easy, because the basic delete routine does
  1512.  * all of the work. Watches for negative arguments,
  1513.  * and does the right thing. If any argument is
  1514.  * present, it kills rather than deletes, to prevent
  1515.  * loss of text if typed with a big argument.
  1516.  * Normally bound to "C-D".
  1517.  */
  1518. /*ARGSUSED*/
  1519. forwdel(f, n, k) {
  1520.     if (n < 0)
  1521.         return (backdel(f, -n, KRANDOM));
  1522.     if (f != FALSE) {            /* Really a kill.    */
  1523.         if ((lastflag&CFKILL) == 0)
  1524.             kdelete();
  1525.         thisflag |= CFKILL;
  1526.     }
  1527.     return (ldelete((RSIZE) n, f ? KFORW : KNONE));
  1528. }
  1529.  
  1530. /*
  1531.  * Delete backwards. This is quite easy too,
  1532.  * because it's all done with other functions. Just
  1533.  * move the cursor back, and delete forwards.
  1534.  * Like delete forward, this actually does a kill
  1535.  * if presented with an argument.
  1536.  */
  1537. /*ARGSUSED*/
  1538. backdel(f, n, k) {
  1539.     register int    s;
  1540.  
  1541.     if (n < 0)
  1542.         return (forwdel(f, -n, KRANDOM));
  1543.     if (f != FALSE) {            /* Really a kill.    */
  1544.         if ((lastflag&CFKILL) == 0)
  1545.             kdelete();
  1546.         thisflag |= CFKILL;
  1547.     }
  1548.     if ((s=backchar(f, n, KRANDOM)) == TRUE)
  1549.         s = ldelete((RSIZE) n, f ? KFORW : KNONE);
  1550.     return (s);
  1551. }
  1552.  
  1553. /*
  1554.  * Kill line. If called without an argument,
  1555.  * it kills from dot to the end of the line, unless it
  1556.  * is at the end of the line, when it kills the newline.
  1557.  * If called with an argument of 0, it kills from the
  1558.  * start of the line to dot. If called with a positive
  1559.  * argument, it kills from dot forward over that number
  1560.  * of newlines. If called with a negative argument it
  1561.  * kills any text before dot on the current line,
  1562.  * then it kills back abs(arg) lines.
  1563.  */
  1564. /*ARGSUSED*/
  1565. killline(f, n, k) {
  1566.     register RSIZE    chunk;
  1567.     register LINE    *nextp;
  1568.     register int    i, c;
  1569.  
  1570.     if ((lastflag&CFKILL) == 0)        /* Clear kill buffer if    */
  1571.         kdelete();            /* last wasn't a kill.    */
  1572.     thisflag |= CFKILL;
  1573.     if (f == FALSE) {
  1574.         for (i = curwp->w_doto; i < llength(curwp->w_dotp); ++i)
  1575.             if ((c = lgetc(curwp->w_dotp, i)) != ' ' && c != '\t')
  1576.                 break;
  1577.         if (i == llength(curwp->w_dotp))
  1578.             chunk = llength(curwp->w_dotp)-curwp->w_doto + 1;
  1579.         else {
  1580.             chunk = llength(curwp->w_dotp)-curwp->w_doto;
  1581.             if (chunk == 0)
  1582.                 chunk = 1;
  1583.         }
  1584.     } else if (n > 0) {
  1585.         chunk = llength(curwp->w_dotp)-curwp->w_doto+1;
  1586.         nextp = lforw(curwp->w_dotp);
  1587.         i = n;
  1588.         while (--i) {
  1589.             if (nextp == curbp->b_linep)
  1590.                 break;
  1591.             chunk += llength(nextp)+1;
  1592.             nextp = lforw(nextp);
  1593.         }
  1594.     } else {                /* n <= 0        */
  1595.         chunk = curwp->w_doto;
  1596.         curwp->w_doto = 0;
  1597.         i = n;
  1598.         while (i++) {
  1599.             if (lback(curwp->w_dotp) == curbp->b_linep)
  1600.                 break;
  1601.             curwp->w_dotp = lback(curwp->w_dotp);
  1602.             curwp->w_flag |= WFMOVE;
  1603.             chunk += llength(curwp->w_dotp)+1;
  1604.         }
  1605.     }
  1606.     /*
  1607.      * KFORW here is a bug. Should be KBACK/KFORW, but we need to
  1608.      * rewrite the ldelete code (later)?
  1609.      */
  1610.     return (ldelete(chunk,  KFORW));
  1611. }
  1612.  
  1613. /*
  1614.  * Yank text back from the kill buffer. This
  1615.  * is really easy. All of the work is done by the
  1616.  * standard insert routines. All you do is run the loop,
  1617.  * and check for errors. The blank
  1618.  * lines are inserted with a call to "newline"
  1619.  * instead of a call to "lnewline" so that the magic
  1620.  * stuff that happens when you type a carriage
  1621.  * return also happens when a carriage return is
  1622.  * yanked back from the kill buffer.
  1623.  * An attempt has been made to fix the cosmetic bug
  1624.  * associated with a yank when dot is on the top line of
  1625.  * the window (nothing moves, because all of the new
  1626.  * text landed off screen).
  1627.  */
  1628. /*ARGSUSED*/
  1629. yank(f, n, k) {
  1630.     register int    c;
  1631.     register int    i;
  1632.     register LINE    *lp;
  1633.     register int    nline;
  1634.  
  1635.     if (n < 0)
  1636.         return (FALSE);
  1637.     nline = 0;                /* Newline counting.    */
  1638.     while (n--) {
  1639.         isetmark();            /* mark around last yank */
  1640.         i = 0;
  1641.         while ((c=kremove(i)) >= 0) {
  1642.             if (c == '\n') {
  1643.                 if (newline(FALSE, 1, KRANDOM) == FALSE)
  1644.                     return (FALSE);
  1645.                 ++nline;
  1646.             } else {
  1647.                 if (linsert((RSIZE) 1, c) == FALSE)
  1648.                     return (FALSE);
  1649.             }
  1650.             ++i;
  1651.         }
  1652.     }
  1653.     lp = curwp->w_linep;            /* Cosmetic adjustment    */
  1654.     if (curwp->w_dotp == lp) {        /* if offscreen insert.    */
  1655.         while (nline-- && lback(lp)!=curbp->b_linep)
  1656.             lp = lback(lp);
  1657.         curwp->w_linep = lp;        /* Adjust framing.    */
  1658.         curwp->w_flag |= WFHARD;
  1659.     }
  1660.     return (TRUE);
  1661. }
  1662. /*
  1663.  * Commands to toggle the four modes. Without an argument, sets the
  1664.  * mode on, with an argument, sets the mode off.
  1665.  */
  1666. /*ARGSUSED*/
  1667. bsmapmode(f, n, k) {
  1668.  
  1669.     if (f == FALSE) mode |= MBSMAP;
  1670.     else mode &= ~MBSMAP;
  1671.     upmodes((BUFFER *) NULL);
  1672.     return TRUE;
  1673. }
  1674.  
  1675. /*ARGSUSED*/
  1676. flowmode(f, n, k) {
  1677.     if (f == FALSE) mode |= MFLOW;
  1678.     else mode &= ~MFLOW;
  1679.     upmodes((BUFFER *) NULL);
  1680.     return TRUE;
  1681. }
  1682.  
  1683. /*ARGSUSED*/
  1684. indentmode(f, n, k) {
  1685.  
  1686.     if (f == FALSE) {
  1687.         mode |= MINDENT;
  1688.         if ((binding[KCTRL|'M'] = symlookup("newline-and-indent"))
  1689.             == NULL)
  1690.             panic("no newline-and-indent in indentmode");
  1691.         if ((binding[KCTRL|'J'] = symlookup("insert-newline")) == NULL)
  1692.             panic("no insert-newline in indentmode");
  1693.     } else {
  1694.         mode &= ~MINDENT;
  1695.         if ((binding[KCTRL|'M'] = symlookup("insert-newline")) == NULL)
  1696.             panic("no insert-newline in indentmode");
  1697.         if ((binding[KCTRL|'J'] = symlookup("newline-and-indent"))
  1698.             == NULL)
  1699.             panic("no newline-and-indent in indentmode");
  1700.     }
  1701.     upmodes((BUFFER *) NULL);
  1702.     return TRUE;
  1703. }    
  1704.  
  1705. /*ARGSUSED*/
  1706. fillmode(f, n, k) {
  1707.  
  1708.     if (f == FALSE) {
  1709.         mode |= MFILL;
  1710.         if ((binding[' '] = symlookup("insert-with-wrap")) == NULL)
  1711.             panic("no insert-with-wrap in fillmode");
  1712.     } else {
  1713.         mode &= ~MFILL;
  1714.         if ((binding[' '] = symlookup("self-insert-command")) == NULL)
  1715.             panic("no self-insert-command in fillmode");
  1716.     }
  1717.     upmodes((BUFFER *) NULL);
  1718.     return TRUE;
  1719. }
  1720. SHAR_EOF
  1721. fi # end of overwriting check
  1722. if test -f 'region.c'
  1723. then
  1724.     echo shar: will not over-write existing file "'region.c'"
  1725. else
  1726. cat << \SHAR_EOF > 'region.c'
  1727. /*
  1728.  *        Region based commands.
  1729.  * The routines in this file
  1730.  * deal with the region, that magic space
  1731.  * between "." and mark. Some functions are
  1732.  * commands. Some functions are just for
  1733.  * internal use.
  1734.  */
  1735. #include    "def.h"
  1736.  
  1737. /*
  1738.  * Kill the region. Ask "getregion"
  1739.  * to figure out the bounds of the region.
  1740.  * Move "." to the start, and kill the characters.
  1741.  */
  1742. /*ARGSUSED*/
  1743. killregion(f, n, k) {
  1744.     register int    s;
  1745.     REGION        region;
  1746.  
  1747.     if ((s=getregion(®ion)) != TRUE)
  1748.         return (s);
  1749.     if ((lastflag&CFKILL) == 0)        /* This is a kill type    */
  1750.         kdelete();            /* command, so do magic    */
  1751.     thisflag |= CFKILL;            /* kill buffer stuff.    */
  1752.     curwp->w_dotp = region.r_linep;
  1753.     curwp->w_doto = region.r_offset;
  1754.     return (ldelete(region.r_size, KFORW));
  1755. }
  1756.  
  1757. /*
  1758.  * Copy all of the characters in the
  1759.  * region to the kill buffer. Don't move dot
  1760.  * at all. This is a bit like a kill region followed
  1761.  * by a yank.
  1762.  */
  1763. /*ARGSUSED*/
  1764. copyregion(f, n, k) {
  1765.     register LINE    *linep;
  1766.     register int    loffs;
  1767.     register int    s;
  1768.     REGION        region;
  1769.  
  1770.     if ((s=getregion(®ion)) != TRUE)
  1771.         return (s);
  1772.     if ((lastflag&CFKILL) == 0)        /* Kill type command.    */
  1773.         kdelete();
  1774.     thisflag |= CFKILL;
  1775.     linep = region.r_linep;            /* Current line.    */
  1776.     loffs = region.r_offset;        /* Current offset.    */
  1777.     while (region.r_size--) {
  1778.         if (loffs == llength(linep)) {    /* End of line.        */
  1779.             if ((s=kinsert('\n', KFORW)) != TRUE)
  1780.                 return (s);
  1781.             linep = lforw(linep);
  1782.             loffs = 0;
  1783.         } else {            /* Middle of line.    */
  1784.             if ((s=kinsert(lgetc(linep, loffs), KFORW)) != TRUE)
  1785.                 return (s);
  1786.             ++loffs;
  1787.         }
  1788.     }
  1789.     return (TRUE);
  1790. }
  1791.  
  1792. /*
  1793.  * Lower case region. Zap all of the upper
  1794.  * case characters in the region to lower case. Use
  1795.  * the region code to set the limits. Scan the buffer,
  1796.  * doing the changes. Call "lchange" to ensure that
  1797.  * redisplay is done in all buffers. 
  1798.  */
  1799. /*ARGSUSED*/
  1800. lowerregion(f, n, k) {
  1801.     register LINE    *linep;
  1802.     register int    loffs;
  1803.     register int    c;
  1804.     register int    s;
  1805.     REGION        region;
  1806.  
  1807.     if ((s=getregion(®ion)) != TRUE)
  1808.         return (s);
  1809.     lchange(WFHARD);
  1810.     linep = region.r_linep;
  1811.     loffs = region.r_offset;
  1812.     while (region.r_size--) {
  1813.         if (loffs == llength(linep)) {
  1814.             linep = lforw(linep);
  1815.             loffs = 0;
  1816.         } else {
  1817.             c = lgetc(linep, loffs);
  1818.             if (ISUPPER(c) != FALSE)
  1819.                 lputc(linep, loffs, TOLOWER(c));
  1820.             ++loffs;
  1821.         }
  1822.     }
  1823.     return (TRUE);
  1824. }
  1825.  
  1826. /*
  1827.  * Upper case region. Zap all of the lower
  1828.  * case characters in the region to upper case. Use
  1829.  * the region code to set the limits. Scan the buffer,
  1830.  * doing the changes. Call "lchange" to ensure that
  1831.  * redisplay is done in all buffers. 
  1832.  */
  1833. /*ARGSUSED*/
  1834. upperregion(f, n, k) {
  1835.     register LINE    *linep;
  1836.     register int    loffs;
  1837.     register int    c;
  1838.     register int    s;
  1839.     REGION        region;
  1840.  
  1841.     if ((s=getregion(®ion)) != TRUE)
  1842.         return (s);
  1843.     lchange(WFHARD);
  1844.     linep = region.r_linep;
  1845.     loffs = region.r_offset;
  1846.     while (region.r_size--) {
  1847.         if (loffs == llength(linep)) {
  1848.             linep = lforw(linep);
  1849.             loffs = 0;
  1850.         } else {
  1851.             c = lgetc(linep, loffs);
  1852.             if (ISLOWER(c) != FALSE)
  1853.                 lputc(linep, loffs, TOUPPER(c));
  1854.             ++loffs;
  1855.         }
  1856.     }
  1857.     return (TRUE);
  1858. }
  1859.  
  1860. /*
  1861.  * This routine figures out the bound of the region
  1862.  * in the current window, and stores the results into the fields
  1863.  * of the REGION structure. Dot and mark are usually close together,
  1864.  * but I don't know the order, so I scan outward from dot, in both
  1865.  * directions, looking for mark. The size is kept in a long. At the
  1866.  * end, after the size is figured out, it is assigned to the size
  1867.  * field of the region structure. If this assignment loses any bits,
  1868.  * then we print an error. This is "type independent" overflow
  1869.  * checking. All of the callers of this routine should be ready to
  1870.  * get an ABORT status, because I might add a "if regions is big,
  1871.  * ask before clobberring" flag.
  1872.  */
  1873. getregion(rp) register REGION *rp; {
  1874.     register LINE    *flp;
  1875.     register LINE    *blp;
  1876.     register long    fsize;            /* Long now.        */
  1877.     register long    bsize;
  1878.  
  1879.     if (curwp->w_markp == NULL) {
  1880.         ewprintf("No mark set in this window");
  1881.         return (FALSE);
  1882.     }
  1883.     if (curwp->w_dotp == curwp->w_markp) {    /* "r_size" always ok.    */
  1884.         rp->r_linep = curwp->w_dotp;
  1885.         if (curwp->w_doto < curwp->w_marko) {
  1886.             rp->r_offset = curwp->w_doto;
  1887.             rp->r_size = (RSIZE) (curwp->w_marko-curwp->w_doto);
  1888.         } else {
  1889.             rp->r_offset = curwp->w_marko;
  1890.             rp->r_size = (RSIZE) (curwp->w_doto-curwp->w_marko);
  1891.         }
  1892.         return (TRUE);
  1893.     }
  1894.     blp = curwp->w_dotp;            /* Get region size.    */
  1895.     flp = curwp->w_dotp;
  1896.     bsize = curwp->w_doto;
  1897.     fsize = llength(flp)-curwp->w_doto+1;
  1898.     while (flp!=curbp->b_linep || lback(blp)!=curbp->b_linep) {
  1899.         if (flp != curbp->b_linep) {
  1900.             flp = lforw(flp);
  1901.             if (flp == curwp->w_markp) {
  1902.                 rp->r_linep = curwp->w_dotp;
  1903.                 rp->r_offset = curwp->w_doto;
  1904.                 return (setsize(rp,
  1905.                     (RSIZE) (fsize+curwp->w_marko)));
  1906.             }
  1907.             fsize += llength(flp)+1;
  1908.         }
  1909.         if (lback(blp) != curbp->b_linep) {
  1910.             blp = lback(blp);
  1911.             bsize += llength(blp)+1;
  1912.             if (blp == curwp->w_markp) {
  1913.                 rp->r_linep = blp;
  1914.                 rp->r_offset = curwp->w_marko;
  1915.                 return (setsize(rp,
  1916.                     (RSIZE) (bsize-curwp->w_marko)));
  1917.             }
  1918.         }
  1919.     }
  1920.     ewprintf("Bug: lost mark");        /* Gak!            */
  1921.     return (FALSE);
  1922. }
  1923.  
  1924. /*
  1925.  * Set size, and check for overflow.
  1926.  */
  1927. setsize(rp, size) register REGION *rp; register RSIZE size; {
  1928.  
  1929.     rp->r_size = size;
  1930.     if (rp->r_size != size) {
  1931.         ewprintf("Region is too large");
  1932.         return (FALSE);
  1933.     }
  1934.     return (TRUE);
  1935. }
  1936.  
  1937. #ifdef    PREFIXREGION
  1938. /*
  1939.  * Implements one of my favorite keyboard macros; put a string at the
  1940.  * beginning of a number of lines in a buffer.  The quote string is
  1941.  * settable by using set-prefix-string.  Great for quoting mail, which
  1942.  * is the real reason I wrote it, but also has uses for creating bar
  1943.  * comments (like the one you're reading) in C code.
  1944.  */
  1945.  
  1946. #define PREFIXLENGTH 40
  1947. static char prefix_string[PREFIXLENGTH] = { '>', '\0' };
  1948.  
  1949. /*
  1950.  * Prefix the region with whatever is in prefix_string.
  1951.  * Leaves dot at the beginning of the line after the end
  1952.  * of the region.  If an argument is given, prompts for the
  1953.  * line prefix string.
  1954.  */
  1955.  
  1956. /*ARGSUSED*/
  1957. prefixregion(f, n, k)
  1958. {
  1959.     register int    s;
  1960.     register LINE    *first, *last;
  1961.     register int    nline;
  1962.     REGION        region;
  1963.     char        *prefix = prefix_string;
  1964.  
  1965.     if ((f == TRUE) && ((s = setprefix(FALSE, 1, KRANDOM)) != TRUE))
  1966.         return (s);
  1967.  
  1968.     /* get # of lines to affect */
  1969.     if ((s = getregion(®ion)) != TRUE)
  1970.         return (s);
  1971.     first = region.r_linep;
  1972.     last = (first == curwp->w_dotp) ? curwp->w_markp : curwp->w_dotp;
  1973.     for (nline = 1; first != last; nline++)
  1974.         first = lforw(first);
  1975.  
  1976.     /*move to beginning of region */
  1977.     curwp->w_dotp = region.r_linep;
  1978.     curwp->w_doto = region.r_offset;
  1979.  
  1980.     /* for each line, go to beginning and insert the prefix string */
  1981.     while (nline--) {
  1982.         gotobol();
  1983.         for (prefix = prefix_string; *prefix; prefix++)
  1984.             (VOID) linsert((RSIZE) 1, *prefix);
  1985.         forwline(FALSE, 1, KRANDOM);
  1986.     }
  1987.     gotobol();
  1988.     return (TRUE);
  1989. }
  1990.  
  1991. /*
  1992.  * Set prefix string.
  1993.  */
  1994.  
  1995. /*ARGSUSED*/
  1996. setprefix(f, n, k)
  1997. {
  1998.     char        buf[PREFIXLENGTH];
  1999.     register int    s;
  2000.  
  2001.     if (prefix_string[0] == '\0')
  2002.         s = ereply("Prefix string: ",buf,sizeof buf);
  2003.     else
  2004.         s = ereply("Prefix string (default %s): ",
  2005.                 buf,sizeof buf,prefix_string);
  2006.     if (s == TRUE)
  2007.         (VOID) strcpy(prefix_string, buf);
  2008.     if ((s == FALSE) && (prefix_string[0] != '\0'))    /* CR -- use old one */
  2009.         s = TRUE;
  2010.     return (s);
  2011. }
  2012. #endif
  2013. SHAR_EOF
  2014. fi # end of overwriting check
  2015. if test -f 'prefix.c'
  2016. then
  2017.     echo shar: will not over-write existing file "'prefix.c'"
  2018. else
  2019. cat << \SHAR_EOF > 'prefix.c'
  2020. /*
  2021.  * This code is a kludge for the two prefix sequences from GNU (well,
  2022.  * the two I want) that uemacs doesn't have. Rather than quadruple the table
  2023.  * space for keys, plus have to test for them everywhere, I'll just kludge
  2024.  * it with functions that are bound to those keys. Later, maybe I'll do
  2025.  * prefixes right.
  2026.  */
  2027.  
  2028. #include "def.h"
  2029.  
  2030. /*ARGSUSED*/
  2031. ctlx4hack(f, n, k) {
  2032.     register KEY    c;
  2033.  
  2034.     if ((c = getkey(KPROMPT)) == 'b' || c == 'B')
  2035.         return poptobuffer(f, n, KRANDOM);
  2036.     if (c == 'f' || c == (KCTRL|'F') || c == 'F')
  2037.         return poptofile(f, n, KRANDOM);
  2038.     
  2039.     if (c == (KCTRL|'G') || c == (KCTLX|KCTRL|'G')
  2040.     ||  c == (KMETA|KCTRL|'G')) {
  2041.         (VOID) ctrlg(FALSE, 1, KRANDOM);
  2042.         return ABORT;
  2043.     }
  2044.     return FALSE;
  2045. }
  2046.  
  2047. /*ARGSUSED*/
  2048. help(f, n, k) {
  2049.     register KEY    c;
  2050.  
  2051.     c = getkey(KPROMPT);
  2052.     while (c == (KCTRL|'H')) {
  2053.         ewprintf("B C: ");
  2054.         c = getkey(0);
  2055.     }
  2056.     if (c == 'b' || c == 'B') return wallchart(f, n, KRANDOM);
  2057.     if (c == 'c' || c == 'C') return desckey(f, n, KRANDOM);
  2058.  
  2059.     if (c == (KCTRL|'G') || c == (KCTLX|KCTRL|'G')
  2060.     ||  c == (KMETA|KCTRL|'G')) {
  2061.         (VOID) ctrlg(FALSE, 1, KRANDOM);
  2062.         return ABORT;
  2063.     }
  2064.     return FALSE;
  2065. }
  2066. SHAR_EOF
  2067. fi # end of overwriting check
  2068. if test -f 'version.c'
  2069. then
  2070.     echo shar: will not over-write existing file "'version.c'"
  2071. else
  2072. cat << \SHAR_EOF > 'version.c'
  2073. /*
  2074.  * This file contains the string that get written 
  2075.  * out by the emacs-version command.
  2076.  * Rich had it generated by a command file. I do
  2077.  * it manually, until I can figure out a way to get
  2078.  * the MicroGnuEmacs version number generated in an
  2079.  * reasonable and automatic manner.
  2080.  */
  2081.  
  2082. char    *version = "MicroGnuEmacs 1a" ;
  2083. SHAR_EOF
  2084. fi # end of overwriting check
  2085. if test -f 'word.c'
  2086. then
  2087.     echo shar: will not over-write existing file "'word.c'"
  2088. else
  2089. cat << \SHAR_EOF > 'word.c'
  2090. /*
  2091.  *        Word mode commands.
  2092.  * The routines in this file
  2093.  * implement commands that work word at
  2094.  * a time. There are all sorts of word mode
  2095.  * commands. If I do any sentence and/or paragraph
  2096.  * mode commands, they are likely to be put in
  2097.  * this file.
  2098.  */
  2099. #include    "def.h"
  2100.  
  2101. /*
  2102.  * Move the cursor backward by
  2103.  * "n" words. All of the details of motion
  2104.  * are performed by the "backchar" and "forwchar"
  2105.  * routines.
  2106.  */
  2107. /*ARGSUSED*/
  2108. backword(f, n, k) {
  2109.     if (n < 0)
  2110.         return (forwword(f, -n, KRANDOM));
  2111.     if (backchar(FALSE, 1, KRANDOM) == FALSE)
  2112.         return (FALSE);
  2113.     while (n--) {
  2114.         while (inword() == FALSE) {
  2115.             if (backchar(FALSE, 1, KRANDOM) == FALSE)
  2116.                 return TRUE;
  2117.         }
  2118.         while (inword() != FALSE) {
  2119.             if (backchar(FALSE, 1, KRANDOM) == FALSE)
  2120.                 return TRUE;
  2121.         }
  2122.     }
  2123.     return (forwchar(FALSE, 1, KRANDOM));
  2124. }
  2125.  
  2126. /*
  2127.  * Move the cursor forward by
  2128.  * the specified number of words. All of the
  2129.  * motion is done by "forwchar".
  2130.  */
  2131. /*ARGSUSED*/
  2132. forwword(f, n, k) {
  2133.     if (n < 0)
  2134.         return (backword(f, -n, KRANDOM));
  2135.     while (n--) {
  2136.         while (inword() == FALSE) {
  2137.             if (forwchar(FALSE, 1, KRANDOM) == FALSE)
  2138.                 return TRUE;
  2139.         }
  2140.         while (inword() != FALSE) {
  2141.             if (forwchar(FALSE, 1, KRANDOM) == FALSE)
  2142.                 return TRUE;
  2143.         }
  2144.     }
  2145.     return (TRUE);
  2146. }
  2147.  
  2148. /*
  2149.  * Move the cursor forward by
  2150.  * the specified number of words. As you move,
  2151.  * convert any characters to upper case.
  2152.  */
  2153. /*ARGSUSED*/
  2154. upperword(f, n, k) {
  2155.     register int    c;
  2156.  
  2157.     if (n < 0)
  2158.         return (FALSE);
  2159.     while (n--) {
  2160.         while (inword() == FALSE) {
  2161.             if (forwchar(FALSE, 1, KRANDOM) == FALSE)
  2162.                 return TRUE;
  2163.         }
  2164.         while (inword() != FALSE) {
  2165.             c = lgetc(curwp->w_dotp, curwp->w_doto);
  2166.             if (ISLOWER(c) != FALSE) {
  2167.                 c = TOUPPER(c);
  2168.                 lputc(curwp->w_dotp, curwp->w_doto, c);
  2169.                 lchange(WFHARD);
  2170.             }
  2171.             if (forwchar(FALSE, 1, KRANDOM) == FALSE)
  2172.                 return TRUE;
  2173.         }
  2174.     }
  2175.     return (TRUE);
  2176. }
  2177.  
  2178. /*
  2179.  * Move the cursor forward by
  2180.  * the specified number of words. As you move
  2181.  * convert characters to lower case.
  2182.  */
  2183. /*ARGSUSED*/
  2184. lowerword(f, n, k) {
  2185.     register int    c;
  2186.  
  2187.     if (n < 0)
  2188.         return (FALSE);
  2189.     while (n--) {
  2190.         while (inword() == FALSE) {
  2191.             if (forwchar(FALSE, 1, KRANDOM) == FALSE)
  2192.                 return TRUE;
  2193.         }
  2194.         while (inword() != FALSE) {
  2195.             c = lgetc(curwp->w_dotp, curwp->w_doto);
  2196.             if (ISUPPER(c) != FALSE) {
  2197.                 c = TOLOWER(c);
  2198.                 lputc(curwp->w_dotp, curwp->w_doto, c);
  2199.                 lchange(WFHARD);
  2200.             }
  2201.             if (forwchar(FALSE, 1, KRANDOM) == FALSE)
  2202.                 return TRUE;
  2203.         }
  2204.     }
  2205.     return (TRUE);
  2206. }
  2207.  
  2208. /*
  2209.  * Move the cursor forward by
  2210.  * the specified number of words. As you move
  2211.  * convert the first character of the word to upper
  2212.  * case, and subsequent characters to lower case. Error
  2213.  * if you try and move past the end of the buffer.
  2214.  */
  2215. /*ARGSUSED*/
  2216. capword(f, n, k) {
  2217.     register int    c;
  2218.  
  2219.     if (n < 0)
  2220.         return (FALSE);
  2221.     while (n--) {
  2222.         while (inword() == FALSE) {
  2223.             if (forwchar(FALSE, 1, KRANDOM) == FALSE)
  2224.                 return TRUE;
  2225.         }
  2226.         if (inword() != FALSE) {
  2227.             c = lgetc(curwp->w_dotp, curwp->w_doto);
  2228.             if (ISLOWER(c) != FALSE) {
  2229.                 c = TOUPPER(c);
  2230.                 lputc(curwp->w_dotp, curwp->w_doto, c);
  2231.                 lchange(WFHARD);
  2232.             }
  2233.             if (forwchar(FALSE, 1, KRANDOM) == FALSE)
  2234.                 return TRUE;
  2235.             while (inword() != FALSE) {
  2236.                 c = lgetc(curwp->w_dotp, curwp->w_doto);
  2237.                 if (ISUPPER(c) != FALSE) {
  2238.                     c = TOLOWER(c);
  2239.                     lputc(curwp->w_dotp, curwp->w_doto, c);
  2240.                     lchange(WFHARD);
  2241.                 }
  2242.                 if (forwchar(FALSE, 1, KRANDOM) == FALSE)
  2243.                     return TRUE;
  2244.             }
  2245.         }
  2246.     }
  2247.     return (TRUE);
  2248. }
  2249.  
  2250. /*
  2251.  * Kill forward by "n" words.
  2252.  */
  2253. /*ARGSUSED*/
  2254. delfword(f, n, k) {
  2255.     register RSIZE    size;
  2256.     register LINE    *dotp;
  2257.     register int    doto;
  2258.  
  2259.     if (n < 0)
  2260.         return (FALSE);
  2261.     if ((lastflag&CFKILL) == 0)        /* Purge kill buffer.    */
  2262.         kdelete();
  2263.     thisflag |= CFKILL;
  2264.     dotp = curwp->w_dotp;
  2265.     doto = curwp->w_doto;
  2266.     size = 0;
  2267.     while (n--) {
  2268.         while (inword() == FALSE) {
  2269.             if (forwchar(FALSE, 1, KRANDOM) == FALSE)
  2270.                 goto out;    /* Hit end of buffer.    */
  2271.             ++size;
  2272.         }
  2273.         while (inword() != FALSE) {
  2274.             if (forwchar(FALSE, 1, KRANDOM) == FALSE)
  2275.                 goto out;    /* Hit end of buffer.    */
  2276.             ++size;
  2277.         }
  2278.     }
  2279. out:
  2280.     curwp->w_dotp = dotp;
  2281.     curwp->w_doto = doto;
  2282.     return (ldelete(size, KFORW));
  2283. }
  2284.  
  2285. /*
  2286.  * Kill backwards by "n" words. The rules
  2287.  * for success and failure are now different, to prevent
  2288.  * strange behavior at the start of the buffer. The command
  2289.  * only fails if something goes wrong with the actual delete
  2290.  * of the characters. It is successful even if no characters
  2291.  * are deleted, or if you say delete 5 words, and there are
  2292.  * only 4 words left. I considered making the first call
  2293.  * to "backchar" special, but decided that that would just
  2294.  * be wierd. Normally this is bound to "M-Rubout" and
  2295.  * to "M-Backspace".
  2296.  */
  2297. /*ARGSUSED*/
  2298. delbword(f, n, k) {
  2299.     register RSIZE    size;
  2300.  
  2301.     if (n < 0)
  2302.         return (FALSE);
  2303.     if ((lastflag&CFKILL) == 0)        /* Purge kill buffer.    */
  2304.         kdelete();
  2305.     thisflag |= CFKILL;
  2306.     if (backchar(FALSE, 1, KRANDOM) == FALSE)
  2307.         return (TRUE);            /* Hit buffer start.    */
  2308.     size = 1;                /* One deleted.        */
  2309.     while (n--) {
  2310.         while (inword() == FALSE) {
  2311.             if (backchar(FALSE, 1, KRANDOM) == FALSE)
  2312.                 goto out;    /* Hit buffer start.    */
  2313.             ++size;
  2314.         }
  2315.         while (inword() != FALSE) {
  2316.             if (backchar(FALSE, 1, KRANDOM) == FALSE)
  2317.                 goto out;    /* Hit buffer start.    */
  2318.             ++size;
  2319.         }
  2320.     }
  2321.     if (forwchar(FALSE, 1, KRANDOM) == FALSE)
  2322.         return (FALSE);
  2323.     --size;                    /* Undo assumed delete.    */
  2324. out:
  2325.     return (ldelete(size, KBACK));
  2326. }
  2327.  
  2328. /*
  2329.  * Return TRUE if the character at dot
  2330.  * is a character that is considered to be
  2331.  * part of a word. The word character list is hard
  2332.  * coded. Should be setable.
  2333.  */
  2334. inword() {
  2335.     if (curwp->w_doto == llength(curwp->w_dotp))
  2336.         return (FALSE);
  2337.     if (ISWORD(lgetc(curwp->w_dotp, curwp->w_doto)) != FALSE)
  2338.         return (TRUE);
  2339.     return (FALSE);
  2340. }
  2341.  
  2342. SHAR_EOF
  2343. fi # end of overwriting check
  2344. #    End of shell archive
  2345. exit 0
  2346. -- 
  2347. Bob Larson
  2348. Arpa: Blarson@Usc-Eclb.Arpa    or    blarson@usc-oberon.arpa
  2349. Uucp: (ihnp4,hplabs,tektronix)!sdcrdcf!usc-oberon!blarson
  2350.  
  2351.